package com.ikingtech.platform.service.system.user.service;

import com.ikingtech.framework.sdk.context.security.Me;
import com.ikingtech.framework.sdk.enums.system.user.UserLockTypeEnum;
import com.ikingtech.framework.sdk.user.api.UserDeptApi;
import com.ikingtech.framework.sdk.user.api.UserPostApi;
import com.ikingtech.framework.sdk.user.api.UserRoleApi;
import com.ikingtech.framework.sdk.user.model.*;
import com.ikingtech.framework.sdk.utils.Tools;
import com.ikingtech.platform.service.system.user.entity.*;
import com.ikingtech.framework.sdk.user.model.*;
import com.ikingtech.platform.service.system.user.entity.*;
import lombok.RequiredArgsConstructor;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RequiredArgsConstructor
public class ModelConverter {

    private final UserSocialRepository userSocialService;

    private final UserCategoryService userCategoryService;

    private final UserDeptRepository userDeptService;

    private final UserRoleRepository userRoleService;

    private final UserPostRepository userPostService;

    private final UserDeptApi userDeptApi;

    private final UserRoleApi userRoleApi;

    private final UserPostApi userPostApi;

    public List<UserDTO> modelBatchConvert(List<UserDO> entities) {
        List<String> userIds = Tools.Coll.convertList(entities, UserDO::getId);
        List<UserRoleDO> userRoleEntities = this.userRoleService.listByDomainCodeAndTenantCodeAndAppCodeAndUserIds(Me.domainCode(), Me.tenantCode(), Me.appCode(), userIds);
        List<UserDeptDO> userDeptEntities = this.userDeptService.listByTenantCodeAndUserIds(Me.tenantCode(), userIds);
        List<UserPostDO> userPostEntities = this.userPostService.listByTenantCodeAndUserIds(Me.tenantCode(), userIds);
        List<UserSocialDO> userSocialEntities = this.userSocialService.listByUserIds(userIds);
        List<UserCategoryDO> userCategoryEntities = this.userCategoryService.listByUserIds(userIds);
        return this.modelBatchConvert(entities, userDeptEntities, userRoleEntities, userPostEntities, userSocialEntities, userCategoryEntities);
    }

    public List<UserDTO> modelBatchConvert(List<UserDO> entities,
                                           List<UserDeptDO> userDeptEntities,
                                           List<UserRoleDO> userRoleEntities,
                                           List<UserPostDO> userPostEntities,
                                           List<UserSocialDO> userSocialEntities,
                                           List<UserCategoryDO> userCategoryEntities) {
        Map<String, List<String>> userDeptIdMap = Tools.Coll.convertGroup(userDeptEntities, UserDeptDO::getUserId, UserDeptDO::getDeptId);
        List<UserDeptDTO> departments = this.userDeptApi.loadByIds(Tools.Coll.convertList(userDeptEntities, UserDeptDO::getDeptId));
        Map<String, UserDeptDTO> deptMap = Tools.Coll.convertMap(departments, UserDeptDTO::getDeptId, dept -> dept);

        Map<String, List<String>> userRoleIdMap = Tools.Coll.convertGroup(userRoleEntities, UserRoleDO::getUserId, UserRoleDO::getRoleId);
        List<UserRoleDTO> roles = this.userRoleApi.loadByIds(Tools.Coll.convertList(userRoleEntities, UserRoleDO::getRoleId));
        Map<String, UserRoleDTO> roleMap = Tools.Coll.convertMap(roles, UserRoleDTO::getRoleId, role -> role);

        Map<String, List<String>> userPostIdMap = Tools.Coll.convertGroup(userPostEntities, UserPostDO::getUserId, UserPostDO::getPostId);
        List<UserPostDTO> posts = this.userPostApi.loadByIds(Tools.Coll.convertList(userPostEntities, UserPostDO::getPostId));
        Map<String, UserPostDTO> postMap = Tools.Coll.convertMap(posts, UserPostDTO::getPostId, post -> post);

        Map<String, List<UserSocialDO>> userSocialMap = Tools.Coll.convertGroup(userSocialEntities, UserSocialDO::getUserId);
        Map<String, List<UserCategoryDO>> userCategoryMap = Tools.Coll.convertGroup(userCategoryEntities, UserCategoryDO::getUserId);

        return Tools.Coll.convertList(entities, entity -> this.modelConvert(entity,
                Tools.Coll.convertList(userDeptIdMap.get(entity.getId()), deptMap::containsKey, deptMap::get),
                Tools.Coll.convertList(userRoleIdMap.get(entity.getId()), roleMap::containsKey, roleMap::get),
                Tools.Coll.convertList(userPostIdMap.get(entity.getId()), postMap::containsKey, postMap::get),
                userSocialMap.get(entity.getId()),
                userCategoryMap.get(entity.getId())));
    }

    public UserDTO modelConvert(UserDO entity) {
        List<UserRoleDO> userRoleEntities = this.userRoleService.listByUserId(entity.getId());
        List<UserDeptDO> userDeptEntities = this.userDeptService.listByUserId(entity.getId());
        List<UserPostDO> userPostEntities = this.userPostService.listByUserId(entity.getId());
        List<UserSocialDO> userSocialEntities = this.userSocialService.listByUserId(entity.getId());
        List<UserCategoryDO> userCategoryEntities = this.userCategoryService.listByUserId(entity.getId());
        List<UserDeptDTO> departments = Tools.Coll.isBlank(userDeptEntities) ? new ArrayList<>() : this.userDeptApi.loadByIds(Tools.Coll.convertList(userDeptEntities, UserDeptDO::getDeptId));
        List<UserRoleDTO> roles = Tools.Coll.isBlank(userRoleEntities) ? new ArrayList<>() : this.userRoleApi.loadByIds(Tools.Coll.convertList(userRoleEntities, UserRoleDO::getRoleId));
        List<UserPostDTO> posts = Tools.Coll.isBlank(userPostEntities) ? new ArrayList<>() : this.userPostApi.loadByIds(Tools.Coll.convertList(userPostEntities, UserPostDO::getPostId));

        return this.modelConvert(entity, departments, roles, posts, userSocialEntities, userCategoryEntities);
    }

    public UserDTO modelConvert(UserDO entity,
                                List<UserDeptDTO> departments,
                                List<UserRoleDTO> roles,
                                List<UserPostDTO> posts,
                                List<UserSocialDO> userSocialEntities,
                                List<UserCategoryDO> userCategoryEntities) {
        UserDTO user = Tools.Bean.copy(entity, UserDTO.class);
        user.setDeptIds(Tools.Coll.convertList(departments, UserDeptDTO::getDeptId));
        user.setDepartments(departments);

        user.setOrganizationIds(departments.stream().map(UserDeptDTO::getOrgId).distinct().collect(Collectors.toList()));

        user.setRoleIds(Tools.Coll.convertList(roles, UserRoleDTO::getRoleId));
        user.setRoles(roles);

        user.setPostIds(Tools.Coll.convertList(posts, UserPostDTO::getPostId));
        user.setPosts(posts);

        user.setCategories(Tools.Coll.convertList(userCategoryEntities, this::convertUserCategory));
        user.setCategoryCodes(Tools.Coll.convertList(userCategoryEntities, userCategoryEntity -> Tools.Str.isNotBlank(userCategoryEntity.getCategoryCode()), UserCategoryDO::getCategoryCode));

        user.setSocials(Tools.Coll.convertList(userSocialEntities, socialEntity -> Tools.Bean.copy(socialEntity, UserSocialDTO.class)));
        user.setLockTypeName(UserLockTypeEnum.valueOf(entity.getLockType()).description);
        return user;
    }

    public UserBasicDTO modelInfoConvert(UserDO entity) {
        return this.modelInfoConvert(entity,  this.userSocialService.listByUserId(entity.getId()), this.userCategoryService.listByUserId(entity.getId()));
    }

    public List<UserBasicDTO> modelInfoConvert(List<UserDO> entities) {
        Map<String, List<UserSocialDO>> userSocialMap = new HashMap<>();
        Map<String, List<UserCategoryDO>> userCategoryMap = new HashMap<>();
        if (Tools.Coll.isNotBlank(entities)) {
            List<UserSocialDO> userSocialEntities = this.userSocialService.listByUserIds(Tools.Coll.convertList(entities, UserDO::getId));
            userSocialMap.putAll(Tools.Coll.convertGroup(userSocialEntities, UserSocialDO::getUserId));

            List<UserCategoryDO> userCategoryEntities = this.userCategoryService.listByUserIds(Tools.Coll.convertList(entities, UserDO::getId));
            userCategoryMap.putAll(Tools.Coll.convertGroup(userCategoryEntities, UserCategoryDO::getUserId));
        }
        return Tools.Coll.convertList(entities, entity -> this.modelInfoConvert(entity, userSocialMap.get(entity.getId()), userCategoryMap.get(entity.getId())));
    }

    public UserBasicDTO modelInfoConvert(UserDO entity, List<UserSocialDO> userSocialEntities, List<UserCategoryDO> userCategoryEntities) {
        UserBasicDTO user = Tools.Bean.copy(entity, UserBasicDTO.class);
        user.setSocials(Tools.Coll.convertList(userSocialEntities, socialEntity -> Tools.Bean.copy(socialEntity, UserSocialDTO.class)));

        user.setCategories(Tools.Coll.convertList(userCategoryEntities, this::convertUserCategory));
        user.setCategoryCodes(Tools.Coll.convertList(userCategoryEntities, userCategoryEntity -> Tools.Str.isNotBlank(userCategoryEntity.getCategoryCode()), UserCategoryDO::getCategoryCode));
        user.setLockTypeName(UserLockTypeEnum.valueOf(entity.getLockType()).description);
        return user;
    }

    public UserCategoryDTO convertUserCategory(UserCategoryDO userCategoryEntity) {
        UserCategoryDTO userCategory = Tools.Bean.copy(userCategoryEntity, UserCategoryDTO.class);
        userCategory.setCategoryName(null == userCategory.getCategory() ? Tools.Str.EMPTY : userCategory.getCategory().description);
        return userCategory;
    }
}
